package ikastola


import beans.FormReceiptRecord
import beans.InvoiceItemRecord
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.text.SimpleDateFormat

import org.ikastola.BalanceFees;
import org.ikastola.DateDiscount
import org.ikastola.Discount
import org.ikastola.Fee
import org.ikastola.FeeDetail;
import org.ikastola.ItemDetail
import org.ikastola.ItemDetailChild;
import org.ikastola.PaymentCheck;
import org.ikastola.Receipt
import org.ikastola.Service
import org.ikastola.Student
import org.joda.time.LocalDate
import org.springframework.transaction.annotation.Transactional

import utils.Utils;

@Transactional
class ReceiptService {
	
	static dateUtilService 
	
	/**
	 * 
	 * @param params
	 * @return
	 */
//	def Receipt saveReceipt(session) {
//		def receiptInstance = session.receipt
//		def balanceFees = session.balances
//		try {
//			receiptInstance = getReceiptInstance(session)
//			balanceFees = getNextFeeBalances(session)
//			if (session.checks) {
//				for (c in session.checks) {
//					c.setDeleted(Constants.NOT_DELETED)
//					c.setClassCreated(new Date())
//					receiptInstance.addToChecks(c)
//				}
//			}
//		} catch (Exception e) {
//			throw new RuntimeException(e)
//		}
		
//		//guarda el recibo
//		receiptInstance.setUuid(0000000);
//		receiptInstance.setDeleted(Constants.NOT_DELETED)
//		receiptInstance.setClassCreated(new Date())
//		receiptInstance.save(flush: true, failOnError: true)
//		
//		//Actualizacion de fechas de pago en servicio del alumno:
//		for (BalanceFees b in balanceFees) {
//			b.setReceipt(receiptInstance)
//			b.setDeleted(Constants.NOT_DELETED)
//			b.save(flush: true, failOnError: true)
//		}
//		
//		return receiptInstance
//    }
	
	/**
	 * Retorna el monto a sumar de interes
	 * 
	 * @param value el monto
	 * @param percent el porcentaje de ese monto
	 * @return monto a sumar
	 */
	def Double getInterest(Double value, Double percent) {
		
		DecimalFormat format = new DecimalFormat("#####0.00")
		DecimalFormatSymbols symbols = new DecimalFormatSymbols();
		char ds = '.'
		char gs = ','
		symbols.setDecimalSeparator(ds)
		symbols.setGroupingSeparator(gs)
		format.setDecimalFormatSymbols(symbols)
		
		Double newValue = value * (percent / 100.0)
		
		return format.parse(format.format(Utils.round(newValue))) 
	}
	
	/**
	 * 
	 * @param params
	 * @return
	 */
	def Receipt confirmReceiptInstance(params, student, session) {

		def discounts = student.getService().getDiscounts()
//		def fees = student.getService().getFees() 
		def formRecords = session.formrecords
		boolean valid = false
		def receiptInstance = new Receipt()
		Double totalDue = 0.0
		Double totalPaid = 0.0
		List discList = []
		List interList = []
		List bonusList = []
		boolean previousDue = false;
		
		for (f in formRecords) {
			String ide = String.valueOf(f.getFee().getId())
			
			if(!params.getAt("ex-fee-"+ide)) {
				
				Double payFee = Double.parseDouble(params.getAt("fee-"+ide)) //lo que se indico a pagar por la tarifa
				System.out.println("Indicado para pagar en tarifa: "+f.getFee().getId()+": "+payFee)
				if (payFee <= 0.0) {
					continue
				}
				
				valid = true;
				totalPaid = Utils.round(totalPaid + payFee)
				
				def feeDetail = new ItemDetail() 
				feeDetail.setName(f.getFee().getName())
				feeDetail.setDescription(f.getFee().getDescription())
				feeDetail.setIsdiscount(Constants.NOT_IS_DISCOUNT)
				feeDetail.setPeriod(f.getFee().getPeriod())
				feeDetail.setValueFee(f.getFee().getValue())				
				feeDetail.setValue(payFee)
				feeDetail.setDeleted(Constants.NOT_DELETED)
				feeDetail.setClassCreated(new Date())
				//fecha a la que corresponde el pago
//				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
//				Date period = format.parse(f.getPeriod()) //params.getAt("period-fee-"+ide))
				feeDetail.setPaymentdate(f.getPeriod())
				
				if (f.getFee().getFeeDetails()) {
					for (fd in f.getFee().getFeeDetails()) {
						ItemDetailChild child = new ItemDetailChild()
						child.setName(fd.getName())
						child.setDescription(fd.getDescription())
						child.setValue(fd.getValue())
						child.setDeleted(Constants.NOT_DELETED)
						child.setClassCreated(new Date())
						feeDetail.addToDetails(child)
					}
				}
				
				receiptInstance.addToDetails(feeDetail)
				
				//total a pagar por la tarifa sin bonificacion ni recargos
				Double due = f.getDue() //Double.parseDouble(params.getAt("due-fee-"+ide))
				if (due == 0.0) {
					previousDue = false
					due =  f.getValue() //Double.parseDouble(params.getAt("val-fee-"+ide))
				} else {
					previousDue = true
				}
				System.out.println("total a pagar sin bonificaciones ni recargos: "+due)
				
				//recargos
				Double inter = f.getInterest() //Double.parseDouble(params.getAt("inter-fee-"+ide))
				if (inter != 0) {
					def itemDetail = new ItemDetail()
					itemDetail.setName("Recargo")
					itemDetail.setValue(inter)
					itemDetail.setValueFee(inter)
					itemDetail.setDescription("Interes mensual - "+f.getFee().getName())
					itemDetail.setIsdiscount(Constants.NOT_IS_DISCOUNT)
					itemDetail.setPeriod(Constants.FEE_PERIOD_MONTH)
					itemDetail.setDeleted(Constants.NOT_DELETED)
					itemDetail.setClassCreated(new Date())
					interList.add(itemDetail)
					totalDue = Utils.round(totalDue + inter)
				}
				
				//bonificaciones
				Double bonus = f.getBonus() //Double.parseDouble(params.getAt("bonus-fee-"+ide))
				if (bonus != 0) {
					//si no se paga el total de la tarifa o los cheques no son inmediatos, no se aplica la bonificacion
					if ((Utils.round(due - bonus + inter)) > payFee || !verifyCheckModes(session.checks)) {
						bonus = 0.0
					} else {
						def itemDetail = new ItemDetail()
						itemDetail.setName("Bonificacion")
						itemDetail.setValue(bonus)
						itemDetail.setValueFee(bonus)
						itemDetail.setDescription("Pago en termino")
						itemDetail.setIsdiscount(Constants.IS_DISCOUNT)
						itemDetail.setPeriod(Constants.FEE_PERIOD_MONTH)
						itemDetail.setDeleted(Constants.NOT_DELETED)
						itemDetail.setClassCreated(new Date())
						bonusList.add(itemDetail)
						totalDue = Utils.round(totalDue - bonus)
					}
				}
								
				totalDue = Utils.round(totalDue + due - payFee)
				
				System.out.println("Deuda total generada fee: "+f.getFee().getId()+ ": "+totalDue)				

				if(!previousDue) {
					for (d in discounts) { //verifico si el descuento aplica sobre el fee actual
						Fee fee = d.getFee()
						if (f.getFee().equals(fee)) { 
							String ided = String.valueOf(d.getId())
							if (!params.getAt("dis-ex-"+ided)) { //verifico si no esta excluido del recibo
								def itemDetail = new ItemDetail()
								itemDetail.setName(d.getName())
								itemDetail.setValue(d.getValue())
								itemDetail.setValueFee(d.getValue())
								itemDetail.setDescription(d.getDescription())
								itemDetail.setIsdiscount(Constants.IS_DISCOUNT)
								itemDetail.setDeleted(Constants.NOT_DELETED)
								itemDetail.setClassCreated(new Date())
								itemDetail.setPeriod(f.getFee().getPeriod())
								discList.add(itemDetail)
							}
						}
					}
				}
			}// else { System.out.println(ide +" fee excluido") }
		}
		
		if(!valid) {
			throw new RuntimeException("No se han seleccionado Tarifas para el Comprobante")
		}
		
		for (itemBonus in bonusList) { //agrego bonificaciones
			receiptInstance.addToDetails(itemBonus)
		}
		
		for (itemDiscount in discList) { //agrego descuentos
			receiptInstance.addToDetails(itemDiscount)
		}
		
		for (itemInter in interList) { //agrego intereses al final
			receiptInstance.addToDetails(itemInter)
		}
		
		//total pagado
		//Double totalPay = Double.parseDouble(params.totalpay) //TODO: controlar total desde UI y calcular de nuevo aca!
		System.out.println("totalpay"+ totalPaid)
		receiptInstance.setTotal(totalPaid)
		
		//deuda generada en el recibo
		receiptInstance.setDue(totalDue)
		
		if (totalDue > 0) {
			receiptInstance.setIstemp(1)
			receiptInstance.setStatus(1)
		} else {
			receiptInstance.setIstemp(0)
			receiptInstance.setStatus(0)
		}
		
		receiptInstance.setStudent(student)
		receiptInstance.setCreationdate(new Date())
		
		return receiptInstance
	}
	
	def verifyCheckModes(checks) {
		boolean valid = true
		if (checks) {
			for (c in checks) {
				if (!Constants.IMMEDIATE_CHECK.equals(c.getMode())) {
					valid = false
					break
				}
			}
		}
		return valid
	}
	
	
	/**
	 * Retorna la lista de balanceFees a dar de alta - (next balance fees )
	 * 
	 * @param params
	 * @param student
	 * @param service
	 * @return
	 */
	def confirmBalanceFees(params, student, session) {
		def balances = []
//		def fees = student.getService().getFees()
		def formRecords = session.formrecords
	
		for (f in formRecords) {
			String ide = String.valueOf(f.getFee().getId())
			
			if(!params.getAt("ex-fee-"+ide)) {
				
				Double payFee = Double.parseDouble(params.getAt("fee-"+ide)) //pagado de la tarifa
				if (payFee <= 0.0) {
					continue
				}
				
				//total de la tarifa con becas y descuentos fijos o deuda anterior
				Double valFee = f.getFinalTotal() //Double.parseDouble(params.getAt("ftot-fee-"+ide)) 
				System.out.println("valFee: "+valFee)
				BalanceFees b = new BalanceFees()
				b.setStudent(student)
				
				//fecha a la que corresponde el pago
//				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
//				Date period = format.parse(params.getAt("period-fee-"+ide))
				b.setPaymentdate(f.getPeriod())
				b.setCreationdate(new Date())
				b.setFee(f.getFee())
				b.setAmount(payFee)
				
				Double due = Utils.round(valFee - payFee) //deuda generada 
				b.setDue(due) 
				
				if (due > 0.0) {
					b.setPaid(0)
				} else {
					b.setPaid(1)
				}
				
				balances.add(b)
			}
		}
		return balances
	}
	
	//bonificaciones
	//				Double feeTotal = 0.0 //A pagar por la tarifa con recargos y bonificaciones
					//bonificaciones
	//				Double bonus = Double.parseDouble(params.getAt("bonus-fee-"+ide))
	//				feeTotal = valFee - bonus
	//				System.out.println(feeTotal)
					//recargos
	//				Double inter = Double.parseDouble(params.getAt("inter-fee-"+ide))
	//				feeTotal = feeTotal + inter
	//				System.out.println(feeTotal)
	 
	
	/**
	 * 
	 * @param params
	 * @return
	 */
//	def Receipt getReceiptInstance(params) throws Exception {
//		
//		Receipt receiptInstance = new Receipt() 
//		
//		Student student = Student.get(params.student)
//		
//		receiptInstance.setStudent(student)
//		
//		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
//
//		Date creationdate = format.parse(params.creationdate)
//		receiptInstance.setCreationdate(creationdate)
//		
//		/*DecimalFormat format = new DecimalFormat("#####0.00")
//		DecimalFormatSymbols symbols = new DecimalFormatSymbols();
//		symbols.setDecimalSeparator(',')
//		symbols.setGroupingSeparator('.')
//		format.setDecimalFormatSymbols(symbols)*/
//		
//		
//		receiptInstance.setTotal(Double.parseDouble(params.total))
//		receiptInstance.setDue(Double.parseDouble(params.due))
//		
//		
//		receiptInstance.setIstemp(Integer.parseInt(params.istemp))
//		receiptInstance.setStatus(Integer.parseInt(params.status))
//		
//		for(d in params.keySet()) {
//			
//			if (d.startsWith("detail-")) {
//				
//				String[] data = params.getAt(d).split("#")
//				Double value = Double.parseDouble(data[2])
//				Double valueFee = Double.parseDouble(data[5])
//				
//				ItemDetail detail = new ItemDetail(name: data[0], isdiscount: data[1], value: value,
//					description: data[3], period: data[4], valueFee: valueFee)
//				
//				String item = d.split("-")[1]
//				
//				if(params.getAt("detpdate-"+item)) {
//					Date paymentdate = format.parse(params.getAt("detpdate-"+item))
//					detail.setPaymentdate(paymentdate)
//				}
//				
//				receiptInstance.addToDetails(detail)
//			}
//		}
//		
//		receiptInstance.setDeleted(0)
//		receiptInstance.setUuid("00001") //Test
//		
//		return receiptInstance	
//	}
	
	
	/**
	 * Obtiene el BalanceFees del fee del alumno
	 * contiendo la fecha del proximo pago sin calcular recargos ni bonificaciones
	 *  
	 * @param student
	 * @return
	 */
	def getFeeBalance(Student s, Fee f) {

		BalanceFees bFee = null
			
		//por cada tarifa recupero el ultimo pago
		List<BalanceFees> balances = BalanceFees.executeQuery("from BalanceFees as b where b.student = ? and b.fee = ? and b.deleted = ? order by b.creationdate desc 1", [s, f, Constants.NOT_DELETED])
		
		if (balances) {
			BalanceFees balance = balances.get(0);
			if (balance.getPaid() == Constants.NOTPAID) {
				//si el ultimo pago esta impago, no importa la fecha.. se presenta la que tenga como paymentdate (a la que corresponde el pago)
				bFee = balance
			}
			else { // Si esta pago 
				bFee = new BalanceFees()
				bFee.setAmount(0)
				bFee.setDue(null)
				bFee.setPaid(Constants.NOTPAID)
				bFee.setFee(f)
				bFee.setCreationdate(new Date())
				//si es mensual: se retorna con el mes siguiente al ultimo pago
				if (Constants.FEE_PERIOD_MONTH.equals(f.getPeriod())) {
					LocalDate lastpayment = new LocalDate(balance.getPaymentdate())
					LocalDate nextpayment = lastpayment.plusMonths(1)
					bFee.setPaymentdate(nextpayment.toDate())
				}
				else //si es anual: se retorna con el proximo año 
				{
					LocalDate lastpayment = new LocalDate(balance.getPaymentdate())
					LocalDate nextpayment = lastpayment.plusYears(1)
					bFee.setPaymentdate(nextpayment.toDate())
				}
			}

		} else {
			//si no tiene pago la retorno con ultima fecha
			bFee = new BalanceFees()
			bFee.setAmount(0)
			bFee.setDue(null)
			bFee.setPaid(Constants.NOTPAID)
			bFee.setFee(f)
			bFee.setPaymentdate(new Date())
			bFee.setCreationdate(new Date())
		}
		
//		System.out.print(((Fee)f[0]).getName())
//		System.out.println((Double)f[1])
//		System.out.println((Date)f[2])
		return bFee
	}
	
	/**
	 * 
	 * @param params
	 * @return
	 */
//	def getNextFeeBalances(params) {
//		def balances = []		
//		for (p in params.keySet()) {
//			if (p.startsWith("bstudent-")) {
//				def idx = p.split("-")[1]
//				Double due = Double.parseDouble(params.getAt("bdue-"+idx))
//				Double amount = Double.parseDouble(params.getAt("bamount-"+idx))
//				Integer paid = Integer.parseInt(params.getAt("bpaid-"+idx))
//				BalanceFees b = new BalanceFees()
//				b.setDue(due)
//				b.setAmount(amount)
//				b.setPaid(paid)
//				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
//				Date paymentdate = format.parse(params.getAt("bpaydate-"+idx))
//				b.setPaymentdate(paymentdate)
//				Date creationdate = format.parse(params.getAt("bcreadate-"+idx))
//				b.setCreationdate(creationdate)
//				Student st = Student.get(params.getAt("bstudent-"+idx))
//				b.setStudent(st)
//				Fee fee = Fee.get(params.getAt("bfee-"+idx))
//				b.setFee(fee)
//				balances.add(b)
//			}
//		}
//		return balances
//	}
	
	/**
	 * 
	 * @param receipt
	 * @return
	 */
	def getInvoiceModel(Receipt receipt) {
		
		def items = []
		
		Integer i = 1
		
		for (ItemDetail item in receipt.getDetails()) {
			InvoiceItemRecord record = new InvoiceItemRecord()
			record.setProductName(item.getName())
			record.setItemNo(String.valueOf(i))
			
			String toPay = '';
			if (Constants.NOT_IS_DISCOUNT.equals(item.getIsdiscount())) {
				toPay = String.valueOf(item.getValue())
			}
			record.setLineTotal(toPay)

			String unitPrice = ''
			if (Constants.NOT_IS_DISCOUNT.equals(item.getIsdiscount())) {
				unitPrice = String.valueOf(item.getValueFee())
			} else {
				unitPrice = String.valueOf(-1*item.getValueFee())
			}
			record.setPrice(unitPrice)
			
			if (item.getPaymentdate()) {
				SimpleDateFormat sdf
				if (Constants.FEE_PERIOD_MONTH.equals(item.getPeriod())) {
					sdf = new SimpleDateFormat(Constants.DATE_FORMAT_MONTH)
					record.setPeriod(sdf.format(item.getPaymentdate()))
				} else {
					sdf = new SimpleDateFormat(Constants.DATE_FORMAT_YEAR)
					record.setPeriod(sdf.format(item.getPaymentdate()))
				}
			} else {
				record.setPeriod(Constants.CHAR_HYPHEN)
			}
			items.add(record)
			
			Integer j = 1
			
			for(ItemDetailChild d in item.getDetails()) {
				InvoiceItemRecord recordDetail = new InvoiceItemRecord()
				recordDetail.setProductName(d.getName())
				recordDetail.setItemNo(String.valueOf(i)+'.'+String.valueOf(j))
				recordDetail.setLineTotal('.')
				recordDetail.setPrice(String.valueOf(d.getValue()))
				recordDetail.setPeriod('.')
				items.add(recordDetail)
				j++
			}
			i++
		}
		return items
	}
	
	

}
